#ifndef _COSMCOMMON_H
#define _COSMCOMMON_H

#include <string>
#include <utility>
#include <vector>
#include <libxml/xmlmemory.h>
#include <iostream>
#include <math.h>

const double latCalc = 39940638/360;    /**< Constant for conversion from latitude to meters. For distance only! */
const double lonCalc = 40041455/360;    /**< Constant for conversion from longitude to meters. For distance only! */

#define JOSM_ACTION_NON (const xmlChar*)""
#define JOSM_ACTION_DEL (const xmlChar*)"delete"
#define JOSM_ACTION_MOD (const xmlChar*)"modify"

/** Tag type definition */
typedef std::pair<const xmlChar*,const xmlChar* > tag_type;

/** Member (int relation) type definition */
typedef struct
{
    const xmlChar* type;
    const xmlChar* role;
    const xmlChar* ref;
}member_type;

class COsmBounds;
class COsmNode;
class COsmWay;
class COsmRelation;

/** Bounds object definition */
class COsmBounds
{
    public:
        double                          minlat;
        double                          minlon;
        double                          maxlat;
        double                          maxlon;
        const xmlChar*                  origin;

        COsmBounds():minlat(0),minlon(0),maxlat(0),maxlon(0),origin((const xmlChar*)""){};
        ~COsmBounds(){};

        void Print()
        {
            using namespace std;
            cout << "Bounds:" << endl;
            cout << "--> minlat: " << minlat << endl;
            cout << "--> maxlat: " << maxlat << endl;
            cout << "--> minlon: " << minlon << endl;
            cout << "--> maxlon: " << maxlon << endl;
            cout << "--> origin: " << origin << endl;
        }
};
typedef COsmBounds* COsmBoundsPtr;

/** OSM Node object definition */
class COsmNode
{
    public:
        long int                        id;
        bool                            visible;
        int                             version;
        const xmlChar*                  timestamp;
        long int                        changeset;
        const xmlChar*                  user;
        long int                        uid;
        const xmlChar*                  action;

        std::vector<tag_type >          tags;

        double                          lat;
        double                          lon;

        /* variables for Astar search */
        std::vector<long int >          neighbours;
        double                          g_score;

        COsmNode():id(-1),visible(true),version(0),timestamp((const xmlChar*)""),changeset(0),user((const xmlChar*)""),uid(-1),action(JOSM_ACTION_NON){};
        ~COsmNode(){};

        double GetDistance(COsmNode* node)
        {
            double latDist = (lat - node->lat)*latCalc;
            double lonDist = (lon - node->lon)*lonCalc;
            return sqrt(latDist*latDist+lonDist*lonDist);
        }

        void Print()
        {
            using namespace std;
            cout << "Node:" << endl;
            cout << "--> id: " << id << endl;
            cout << "--> visible: " << visible << endl;
            cout << "--> version: " << version << endl;
            cout << "--> timestamp: " << timestamp << endl;
            cout << "--> changeset: " << changeset << endl;
            cout << "--> user: " << user << endl;
            cout << "--> uid: " << uid << endl;
            cout << "--> action: " << action << endl;
            cout << "--> lat: " << lat << endl;
            cout << "--> lon: " << lon << endl;
            cout << "--> Number of tags: " << tags.size() << endl;
            for(unsigned int i = 0; i < tags.size(); i++)
                cout << "----> Tag k='" << tags[i].first << "' v='" << tags[i].second << "'" << endl;
            cout << "--> Number of neighbours: " << neighbours.size() << endl;
            for(unsigned int i = 0; i < neighbours.size(); i++)
                cout << "----> Neighbour index: " << neighbours[i] << endl;
        }
};
typedef COsmNode* COsmNodePtr;

/** OSM Way object definition */
class COsmWay
{
    public:
        long int                        id;
        bool                            visible;
        const xmlChar*                  timestamp;
        int                             version;
        long int                        changeset;
        const xmlChar*                  user;
        long int                        uid;
        const xmlChar*                  action;

        std::vector<tag_type >          tags;

        std::vector<long int >          nodes;

        COsmWay():id(-1),visible(true),timestamp((const xmlChar*)""),version(0),changeset(0),user((const xmlChar*)""),uid(-1),action(JOSM_ACTION_NON){};
        ~COsmWay(){};

        void Print()
        {
            using namespace std;
            cout << "Way:" << endl;
            cout << "--> id: " << id << endl;
            cout << "--> visible: " << visible << endl;
            cout << "--> timestamp: " << timestamp << endl;
            cout << "--> version: " << version << endl;
            cout << "--> changeset: " << changeset << endl;
            cout << "--> user: " << user << endl;
            cout << "--> uid: " << uid << endl;
            cout << "--> action: " << action << endl;
            cout << "--> Number of nodes: " << nodes.size() << endl;
            for(unsigned int i = 0; i < nodes.size(); i++)
                cout << "----> Ref. node index: " << nodes[i] << endl;
            cout << "--> Number of tags: " << tags.size() << endl;
            for(unsigned int i = 0; i < tags.size(); i++)
                cout << "----> Tag k='" << tags[i].first << "' v='" << tags[i].second << "'" << endl;
        }
};
typedef COsmWay* COsmWayPtr;

/** OSM Realation object definition */
class COsmRelation
{
    public:
        long int                        id;
        bool                            visible;
        const xmlChar*                  timestamp;
        int                             version;
        long int                        changeset;
        const xmlChar*                  user;
        long int                        uid;
        const xmlChar*                  action;

        std::vector<tag_type >          tags;

        std::vector<member_type >       members;

        COsmRelation():id(-1),visible(true),timestamp((const xmlChar*)""),version(0),changeset(0),user((const xmlChar*)""),uid(-1),action(JOSM_ACTION_NON){};
        ~COsmRelation(){};

        void Print()
        {
            using namespace std;
            cout << "Relation:" << endl;
            cout << "--> id: " << id << endl;
            cout << "--> visible: " << visible << endl;
            cout << "--> timestamp: " << timestamp << endl;
            cout << "--> version: " << version << endl;
            cout << "--> changeset: " << changeset << endl;
            cout << "--> user: " << user << endl;
            cout << "--> uid: " << uid << endl;
            cout << "--> action: " << action << endl;
            cout << "--> Number of members: " << members.size() << endl;
            for(unsigned int i = 0; i < members.size(); i++)
                cout << "----> Member type=" << members[i].type << " role=" << members[i].role << " ref=" << members[i].ref << endl;
            cout << "--> Number of tags: " << tags.size() << endl;
            for(unsigned int i = 0; i < tags.size(); i++)
                cout << "----> Tag k='" << tags[i].first << "' v='" << tags[i].second << "'" << endl;
        }
};
typedef COsmRelation* COsmRelationPtr;

#endif
